<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AI代码生成器</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.8.0/styles/github.min.css">
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/highlight.js@11.8.0/lib/highlight.min.js"></script>
  <script>
    // 确保highlight.js正确加载
    if (typeof hljs === 'undefined') {
      console.warn('highlight.js not loaded, using fallback');
      window.hljs = {
        highlightElement: function(el) {
          // 简单的fallback
          el.style.backgroundColor = '#f8f9fa';
        },
        getLanguage: function() { return false; },
        highlight: function(code) { return code; },
        highlightAuto: function(code) { return code; }
      };
    }
  </script>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      padding: 20px;
    }

    .app {
      max-width: 1200px;
      margin: 0 auto;
      background: rgba(255, 255, 255, 0.95);
      border-radius: 20px;
      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
      backdrop-filter: blur(10px);
      overflow: hidden;
    }

    .header {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
      padding: 30px;
      text-align: center;
    }

    .header h1 {
      font-size: 2.5rem;
      margin-bottom: 10px;
      font-weight: 300;
    }

    .header p {
      opacity: 0.9;
      font-size: 1.1rem;
    }

    .content {
      padding: 40px;
    }

    .form-group {
      margin-bottom: 25px;
    }

    .form-group label {
      display: block;
      font-weight: 600;
      color: #333;
      margin-bottom: 8px;
      font-size: 1rem;
    }

    .form-control {
      width: 100%;
      padding: 15px;
      border: 2px solid #e1e5e9;
      border-radius: 12px;
      font-size: 1rem;
      transition: all 0.3s ease;
      background: #fff;
    }

    .form-control:focus {
      outline: none;
      border-color: #667eea;
      box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
    }

    textarea.form-control {
      resize: vertical;
      min-height: 120px;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    }

    .btn {
      padding: 15px 30px;
      border: none;
      border-radius: 12px;
      font-size: 1rem;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.3s ease;
      margin-right: 15px;
      margin-bottom: 10px;
    }

    .btn-primary {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
    }

    .btn-primary:hover:not(:disabled) {
      transform: translateY(-2px);
      box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
    }

    .btn-secondary {
      background: #6c757d;
      color: white;
    }

    .btn-secondary:hover {
      background: #5a6268;
      transform: translateY(-2px);
    }

    .btn:disabled {
      opacity: 0.6;
      cursor: not-allowed;
      transform: none !important;
    }

    .status {
      padding: 15px;
      border-radius: 12px;
      margin: 20px 0;
      font-weight: 600;
      display: none;
    }

    .status.show {
      display: block;
    }

    .status.success {
      background: #d4edda;
      color: #155724;
      border: 1px solid #c3e6cb;
    }

    .status.error {
      background: #f8d7da;
      color: #721c24;
      border: 1px solid #f5c6cb;
    }

    .status.info {
      background: #d1ecf1;
      color: #0c5460;
      border: 1px solid #bee5eb;
    }

    .output-container {
      margin-top: 30px;
      border: 2px solid #e1e5e9;
      border-radius: 15px;
      overflow: hidden;
      background: #fff;
    }

    .output-header {
      background: #f8f9fa;
      padding: 20px;
      border-bottom: 2px solid #e1e5e9;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .output-header h3 {
      color: #333;
      font-weight: 600;
    }

    .output {
      padding: 30px;
      min-height: 400px;
      line-height: 1.8;
      background: #fff;
    }

    .markdown-content {
      font-size: 1rem;
    }

    .markdown-content pre {
      background: #f8f9fa;
      padding: 20px;
      border-radius: 8px;
      overflow-x: auto;
      margin: 15px 0;
    }

    .markdown-content code {
      background: #f1f3f4;
      padding: 2px 6px;
      border-radius: 4px;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    }

    .markdown-content pre code {
      background: transparent;
      padding: 0;
    }

    .loading {
      display: inline-block;
      width: 20px;
      height: 20px;
      border: 3px solid #f3f3f3;
      border-top: 3px solid #667eea;
      border-radius: 50%;
      animation: spin 1s linear infinite;
      margin-right: 10px;
    }

    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    .empty-state {
      text-align: center;
      color: #6c757d;
      padding: 60px 20px;
    }

    .empty-state-icon {
      font-size: 4rem;
      margin-bottom: 20px;
    }

    .typing-indicator {
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 40px;
      color: #667eea;
      font-size: 1.1rem;
    }

    .progress-bar {
      width: 100%;
      height: 4px;
      background: #e1e5e9;
      border-radius: 2px;
      overflow: hidden;
      margin-top: 10px;
    }

    .progress-fill {
      height: 100%;
      background: linear-gradient(90deg, #667eea, #764ba2);
      width: 0%;
      transition: width 0.3s ease;
      animation: progress 2s ease-in-out infinite;
    }

    @keyframes progress {
      0% { width: 0%; }
      50% { width: 70%; }
      100% { width: 100%; }
    }

    @media (max-width: 768px) {
      .content {
        padding: 20px;
      }
      
      .header h1 {
        font-size: 2rem;
      }
      
      .output-header {
        flex-direction: column;
        gap: 15px;
      }
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="app">
      <div class="header">
        <h1>🤖 AI代码生成器</h1>
        <p>基于飞书文档智能生成API代码和测试用例</p>
      </div>

      <div class="content">
        <div class="form-group">
          <label for="url">飞书文档URL:</label>
          <input 
            type="text" 
            id="url" 
            class="form-control" 
            v-model="formData.url"
            placeholder="https://open.feishu.cn/..."
          >
        </div>

        <div class="form-group">
          <label for="template">自定义模板 (可选):</label>
          <textarea 
            id="template" 
            class="form-control" 
            v-model="formData.template"
            placeholder="使用默认模板或输入自定义模板..."
          ></textarea>
        </div>

        <button 
          @click="generateCode" 
          :disabled="isGenerating"
          class="btn btn-primary"
        >
          <span v-if="isGenerating" class="loading"></span>
          {{ isGenerating ? '生成中...' : '🚀 生成代码' }}
        </button>
        
        <button @click="clearOutput" class="btn btn-secondary">🗑️ 清空输出</button>

        <div 
          v-if="status.show" 
          :class="['status', status.type, 'show']"
        >
          {{ status.message }}
        </div>

        <div class="output-container">
          <div class="output-header">
            <h3>📝 生成结果</h3>
            <div>
              <button @click="copyToClipboard" class="btn btn-secondary">📋 复制</button>
              <button @click="downloadAsFile" class="btn btn-secondary">💾 下载</button>
            </div>
          </div>
          <div class="output" id="output">
            <div v-if="!outputContent && !isGenerating" class="empty-state">
              <div class="empty-state-icon">📄</div>
              <div>等待生成代码...</div>
            </div>
            <div v-else-if="isGenerating && !outputContent" class="typing-indicator">
              <div class="loading"></div>
              <div>AI正在思考中...</div>
              <div class="progress-bar">
                <div class="progress-fill"></div>
              </div>
            </div>
            <div v-else v-html="outputContent" class="markdown-content"></div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    const { createApp, ref, reactive, onMounted, onUnmounted } = Vue;

    createApp({
      setup() {
        const API_BASE = 'http://localhost:8000';
        const isGenerating = ref(false);
        const outputContent = ref('');
        const rawOutput = ref('');
        let currentEventSource = null; // 存储当前的EventSource连接

        const formData = reactive({
          url: '',
          template: ''
        });

        const status = reactive({
          show: false,
          message: '',
          type: 'info'
        });

        // 配置marked
        marked.setOptions({
          highlight: (code, lang) => {
            if (lang && hljs.getLanguage(lang)) {
              return hljs.highlight(code, { language: lang }).value;
            }
            return hljs.highlightAuto(code).value;
          },
          breaks: true,
          gfm: true
        });

        // 清理EventSource连接
        function cleanupEventSource() {
          if (currentEventSource) {
            try {
              currentEventSource.close();
            } catch (e) {
              console.log('Error closing EventSource:', e);
            }
            currentEventSource = null;
          }
        }

        function showStatus(message, type = 'info') {
          status.message = message;
          status.type = type;
          status.show = true;
        }

        function hideStatus() {
          status.show = false;
        }

        function clearOutput() {
          outputContent.value = '';
          rawOutput.value = '';
          hideStatus();
          cleanupEventSource();
        }

        function updateDisplay(markdownText) {
          try {
            if (markdownText.trim()) {
              const html = marked.parse(markdownText);
              outputContent.value = html;
              // 高亮代码块
              setTimeout(() => {
                document.querySelectorAll('pre code').forEach(block => {
                  hljs.highlightElement(block);
                });
              }, 100);
            } else {
              outputContent.value = '';
            }
          } catch (e) {
            console.log('Markdown parsing failed, using plain text:', e);
            outputContent.value = `<pre>${markdownText}</pre>`;
          }
        }

        async function generateCode() {
          const url = formData.url.trim();
          const template = formData.template.trim();

          if (!url) {
            showStatus('请提供飞书文档URL', 'error');
            return;
          }

          const req = { 
            url,
            ...(template && { template }) 
          };

          isGenerating.value = true;
          showStatus('正在生成代码...', 'info');
          outputContent.value = '';
          rawOutput.value = '';

          try {
            const response = await fetch(`${API_BASE}/generate-code`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify(req)
            });

            if (!response.ok) {
              throw new Error(`HTTP ${response.status}`);
            }

            const result = await response.json();
            const taskId = result.task_id;

            if (!taskId) {
              throw new Error('未获取到任务ID');
            }

            currentEventSource = new EventSource(`${API_BASE}/generate-code-stream?task_id=${taskId}`);
            let accumulatedData = '';

            // 监听消息事件
            currentEventSource.onmessage = function(event) {
              const data = event.data;
              
              // 检查是否是结束标记
              if (data === '[DONE]') {
                console.log('Received completion signal');
                clearTimeout(timeout);
                if (currentEventSource) {
                  currentEventSource.close();
                  currentEventSource = null;
                }
                showStatus('生成完成!', 'success');
                isGenerating.value = false;
                return;
              }
              
              // if (data && data.trim()) {
                accumulatedData += data;
                rawOutput.value = accumulatedData;
                console.log('Received data chunk:', data);
                console.log('Total accumulated data length:', accumulatedData.length);

                // 实时更新显示
                updateDisplay(accumulatedData);
              // }
            };

            // 监听错误事件
            currentEventSource.onerror = function(event) {
              // 检查连接状态，避免在正常关闭时触发错误
              if (currentEventSource && currentEventSource.readyState === EventSource.CLOSED) {
                console.log('EventSource connection closed normally');
                return;
              }
              
              console.error('EventSource error:', event);
              clearTimeout(timeout);
              if (currentEventSource) {
                currentEventSource.close();
                currentEventSource = null;
              }
              showStatus('连接错误', 'error');
              isGenerating.value = false;
            };

            // 监听连接打开事件
            currentEventSource.onopen = function(event) {
              console.log('EventSource connection opened');
            };

            // 设置超时处理
            const timeout = setTimeout(() => {
              if (currentEventSource) {
                currentEventSource.close();
                currentEventSource = null;
              }
              showStatus('连接超时', 'error');
              isGenerating.value = false;
            }, 300000);

          } catch (err) {
            console.error('Error in generateCode:', err);
            showStatus(`错误: ${err.message}`, 'error');
            isGenerating.value = false;
          }
        }

        function copyToClipboard() {
          const text = rawOutput.value || document.getElementById('output').textContent;
          navigator.clipboard.writeText(text).then(() => {
            showStatus('已复制到剪贴板', 'success');
          }).catch(() => {
            showStatus('复制失败', 'error');
          });
        }

        function downloadAsFile() {
          const text = rawOutput.value || document.getElementById('output').textContent;
          const blob = new Blob([text], { type: 'text/plain' });
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = `generated_code_${new Date().toISOString().replace(/[:.]/g, '-')}.md`;
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(url);
          showStatus('文件已下载!', 'success');
        }

        // 键盘快捷键
        function handleKeydown(e) {
          if ((e.ctrlKey || e.metaKey) && e.key === 'Enter' && !isGenerating.value) {
            e.preventDefault();
            generateCode();
          }
        }

        onMounted(() => {
          document.addEventListener('keydown', handleKeydown);
        });

        // 组件卸载时清理资源
        onUnmounted(() => {
          document.removeEventListener('keydown', handleKeydown);
          cleanupEventSource();
        });

        return {
          formData,
          isGenerating,
          outputContent,
          status,
          generateCode,
          clearOutput,
          copyToClipboard,
          downloadAsFile
        };
      }
    }).mount('#app');
  </script>
</body>
</html>
